﻿using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Windows.Forms;
using System.IO;
using System.Diagnostics;

namespace CreateHyperVServerUSB
{
    public partial class MainForm : Form
    {

        #region "fields"

            private System.Resources.ResourceManager _currentResource = null;

        #endregion

        #region "Constructor"

            public MainForm()
            {
                Load += MainForm_Load;
                InitializeComponent();
            }
        
        #endregion

        #region "Event Methods"

            private void MainForm_Load(System.Object sender, System.EventArgs e)
            {
                LocalizeEnglish();

                SetDriveList(TargetDriveComboBox);

                SetInstallWimPath();

                SetWindowsAIKPath();

                SetLanguageComboBox();

            }


            private void runButton_Click(System.Object sender, System.EventArgs e)
            {

                try
                {
                    this.runButton.Enabled = false;
                    this.Refresh();

                    if (IsInputCheck() == false)
                    {
                        return;
                    }

                    string vhdFileName = Path.GetTempFileName();
                    vhdFileName = System.IO.Path.ChangeExtension(vhdFileName, ".vhd");

                    if (File.Exists(vhdFileName))
                    {
                        System.IO.File.Delete(vhdFileName);
                    }

                    string vhdDriveLetter = GetAvailableDriveLetter();
                    if (string.IsNullOrEmpty(vhdDriveLetter))
                    {
                        MessageBox.Show(_currentResource.GetString("Message1"), Application.ProductName, MessageBoxButtons.OK, MessageBoxIcon.Warning);
                        return;
                    }

                    vhdDriveLetter = vhdDriveLetter.Replace(":", string.Empty).Replace("\\", string.Empty);
                    string usbDriveLetter = this.TargetDriveComboBox.SelectedValue.ToString().Replace(":", string.Empty).Replace("\\", string.Empty);

                    //
                    // STEP 1
                    //
                    DateTime startTime = DateTime.Now;

                    this.ProgressListBox.Items.Clear();
                    this.ProgressListBox.Items.Add(string.Format(_currentResource.GetString("Message2"), startTime.ToString("yyyy/MM/dd HH:mm:ss")));
                    this.ProgressListBox.Items.Add(string.Empty);
                    this.ProgressListBox.Items.Add(_currentResource.GetString("Message3"));
                    this.ProgressListBox.Items.Add(string.Format(_currentResource.GetString("Message4"), vhdFileName, vhdDriveLetter));

                    UpdateStepPanel(this.Step1Panel);

                    this.Refresh();

                    List<string> diskPartScriptList = new List<string>();

                    diskPartScriptList.Clear();
                    diskPartScriptList.Add(string.Format("create vdisk file=\"{0}\" maximum=12288 type=fixed", vhdFileName));
                    diskPartScriptList.Add(string.Format("select vdisk file=\"{0}\"", vhdFileName));
                    diskPartScriptList.Add("attach vdisk");
                    diskPartScriptList.Add("create partition primary");
                    diskPartScriptList.Add(string.Format("assign letter={0}", vhdDriveLetter));
                    diskPartScriptList.Add("format quick fs=ntfs label=hyperV");

                    ExecuteDiskPartCommand(diskPartScriptList);

                    //
                    // STEP 2
                    //
                    this.ProgressListBox.Items.Add(string.Empty);
                    this.ProgressListBox.Items.Add(_currentResource.GetString("Message5"));

                    UpdateStepPanel(this.Step2Panel);

                    this.Refresh();

                    string imageExePath = System.IO.Path.Combine(this.windowsAIKPathTextBox.Text, "imagex.exe");
                    string imageExeArgument = string.Format("/apply \"{0}\" 1 {1}", this.installWimTextBox.Text, vhdDriveLetter + ":\\");
                    ExecuteCommand(imageExePath, imageExeArgument);

                    string dismExePath = "dism.exe";
                    string dismExeArgument = string.Format("/image:{0}: /Set-AllIntl:{1}", vhdDriveLetter, this.LanguageComboBox.SelectedValue.ToString());
                    ExecuteCommand(dismExePath, dismExeArgument);

                    dismExePath = "dism.exe";
                    dismExeArgument = string.Format("/image:{0}: /Set-LayeredDriver:{1}", vhdDriveLetter, this.keyBoardComboBox.SelectedValue.ToString());
                    ExecuteCommand(dismExePath, dismExeArgument);

                    diskPartScriptList.Clear();
                    diskPartScriptList.Add(string.Format("select vdisk file=\"{0}\"", vhdFileName));
                    diskPartScriptList.Add("detach vdisk");

                    ExecuteDiskPartCommand(diskPartScriptList);

                    //
                    // STEP 3
                    //
                    this.ProgressListBox.Items.Add(string.Empty);
                    this.ProgressListBox.Items.Add(_currentResource.GetString("Message6"));

                    UpdateStepPanel(this.Step3Panel);

                    this.Refresh();

                    string roboCopyExePath = "robocopy.exe";
                    string roboCopyExePathArgument = string.Format("\"{0}\" {1}:\\ \"{2}\"", System.IO.Path.GetDirectoryName(vhdFileName), usbDriveLetter, System.IO.Path.GetFileName(vhdFileName));

                    ExecuteCommand(roboCopyExePath, roboCopyExePathArgument);

                    //
                    // STEP 4
                    //
                    this.ProgressListBox.Items.Add(string.Empty);
                    this.ProgressListBox.Items.Add(_currentResource.GetString("Message7"));

                    UpdateStepPanel(this.Step4Panel);

                    this.Refresh();

                    string bootSectExePath = System.IO.Path.Combine(this.windowsAIKPathTextBox.Text.Replace("\\x86", "\\PETools\\x86"), "bootsect.exe");
                    string bootSectExeArgument = string.Format("/nt60 {0}: /force /mbr", usbDriveLetter);

                    ExecuteCommand(bootSectExePath, bootSectExeArgument);

                    diskPartScriptList.Clear();
                    diskPartScriptList.Add(string.Format("select vdisk file=\"{0}\"", usbDriveLetter + ":\\" + System.IO.Path.GetFileName(vhdFileName)));
                    diskPartScriptList.Add("attach vdisk");

                    ExecuteDiskPartCommand(diskPartScriptList);

                    string bootBootExePath = System.IO.Path.Combine(this.windowsAIKPathTextBox.Text, "bcdboot.exe");
                    string bootBootExeArgument = string.Format("{0}:\\windows /s {1}:", vhdDriveLetter, usbDriveLetter);

                    ExecuteCommand(bootBootExePath, bootBootExeArgument);

                    string regExePath = "reg.exe";
                    string regExeArgument = string.Empty;

                    regExeArgument = string.Format("load HKLM\\HyperVTemp {0}:\\windows\\system32\\config\\system", vhdDriveLetter);
                    ExecuteCommand(regExePath, regExeArgument);

                    regExeArgument = "add \"HKLM\\HyperVTemp\\ControlSet001\\Control\\Session Manager\\Memory Management\" /v PagingFiles /t REG_MULTI_SZ /d \"\" /f";
                    ExecuteCommand(regExePath, regExeArgument);

                    regExeArgument = "delete \"HKLM\\HyperVTemp\\ControlSet001\\Control\\Session Manager\\Memory Management\" /v ExistingPageFiles /f";
                    ExecuteCommand(regExePath, regExeArgument);

                    regExeArgument = "unload HKLM\\HyperVTemp";
                    ExecuteCommand(regExePath, regExeArgument);

                    diskPartScriptList.Clear();
                    diskPartScriptList.Add(string.Format("select vdisk file=\"{0}\"", usbDriveLetter + ":\\" + System.IO.Path.GetFileName(vhdFileName)));
                    diskPartScriptList.Add("detach vdisk");

                    ExecuteDiskPartCommand(diskPartScriptList);

                    if (File.Exists(vhdFileName))
                    {
                        System.IO.File.Delete(vhdFileName);
                    }

                    DateTime finishTime = DateTime.Now;

                    TimeSpan ts = finishTime - startTime;

                    this.ProgressListBox.Items.Add(string.Empty);
                    this.ProgressListBox.Items.Add(string.Format(_currentResource.GetString("Message8"), DateTime.Now.ToString("yyyy/MM/dd HH:mm:ss"), ts.ToString()));

                }
                finally
                {
                    this.runButton.Enabled = true;

                }

            }


            private void browseWindowsAikButton_Click(System.Object sender, System.EventArgs e)
            {
                if (!string.IsNullOrEmpty(this.windowsAIKPathTextBox.Text))
                {
                    aikFolderBrowserDialog.SelectedPath = this.windowsAIKPathTextBox.Text;
                }

                aikFolderBrowserDialog.Description = _currentResource.GetString("Message15") + "\r\n" + "Windows AIK\\Tools\\" + Environment.GetEnvironmentVariable("PROCESSOR_ARCHITECTURE");


                if (aikFolderBrowserDialog.ShowDialog() == System.Windows.Forms.DialogResult.OK)
                {
                    this.windowsAIKPathTextBox.Text = aikFolderBrowserDialog.SelectedPath;

                }

            }


            private void browseInstallWimButton_Click(System.Object sender, System.EventArgs e)
            {
                if (!string.IsNullOrEmpty(this.installWimTextBox.Text))
                {
                    this.wimOpenFileDialog.InitialDirectory = System.IO.Path.GetDirectoryName(this.installWimTextBox.Text);
                    this.wimOpenFileDialog.FileName = System.IO.Path.GetFileName(this.installWimTextBox.Text);
                }


                if (wimOpenFileDialog.ShowDialog() == System.Windows.Forms.DialogResult.OK)
                {
                    this.installWimTextBox.Text = wimOpenFileDialog.FileName;

                }

            }


            private void EnglishToolStripMenuItem_Click(System.Object sender, System.EventArgs e)
            {

                LocalizeEnglish();

            }

            private void JapaneseToolStripMenuItem_Click(System.Object sender, System.EventArgs e)
            {
                LocalizeJapanease();

            }

        #endregion

        #region "Private Methods"


            private void SetDriveList(ComboBox targetComboBox)
    {
	    targetComboBox.DropDownStyle = ComboBoxStyle.DropDownList;

	    DataTable driveTable = new DataTable();
	    driveTable.TableName = "DriveTable";

	    driveTable.Columns.Add("VALUE", typeof(string));
	    driveTable.Columns.Add("DISPLAY", typeof(string));
	    driveTable.Columns.Add("SOURCE", typeof(DriveInfo));

	    List<DriveInfo> driveList = DriveInfo.GetDrives().ToList();

	    foreach (DriveInfo driveItem in driveList) {

		    if ((driveItem.IsReady) && (driveItem.DriveType != DriveType.Network) && (driveItem.DriveType != DriveType.CDRom)) {
			    DataRow row = driveTable.Rows.Add();

			    row["VALUE"] = driveItem.Name;
			    row["DISPLAY"] = string.Format("{0}({1} Disk)", driveItem.Name, driveItem.DriveType.ToString());
			    row["SOURCE"] = driveItem;

		    }

	    }

	    targetComboBox.DataSource = driveTable;
	    targetComboBox.ValueMember = "VALUE";
	    targetComboBox.DisplayMember = "DISPLAY";

	    DriveInfo firstSelectDrive = (from aDrive in DriveInfo.GetDrives().ToList() 
                                      where aDrive.IsReady && aDrive.DriveType == DriveType.Removable
                                      select aDrive).FirstOrDefault();


	    if ((firstSelectDrive != null)) {
		    targetComboBox.SelectedValue = firstSelectDrive.Name;

	    }

    }


            private void SetInstallWimPath()
    {
	    DataTable driveTable = new DataTable();
	    driveTable.TableName = "DriveTable";

	    driveTable.Columns.Add("VALUE", typeof(string));
	    driveTable.Columns.Add("DISPLAY", typeof(string));
	    driveTable.Columns.Add("SOURCE", typeof(DriveInfo));

	    List<DriveInfo> driveList = (from aDrive in DriveInfo.GetDrives().ToList()
                                     where aDrive.IsReady && aDrive.DriveType == DriveType.CDRom
                                     select aDrive).ToList();


	    if ((driveList != null)) {
		    driveList.Reverse();

		    foreach (DriveInfo driveItem in driveList) {
			    string installWimPath = string.Format("{0}{1}", driveItem.Name, "sources\\install.wim");
			    if (File.Exists(installWimPath)) {
				    this.installWimTextBox.Text = installWimPath;
				    break; // TODO: might not be correct. Was : Exit For
			    }

		    }

	    }

    }


            private void SetWindowsAIKPath()
            {
                string aikPath = "C:\\Program Files\\Windows AIK\\Tools";
                aikPath = System.IO.Path.Combine(aikPath, Environment.GetEnvironmentVariable("PROCESSOR_ARCHITECTURE"));
                this.windowsAIKPathTextBox.Text = aikPath;
            }

            private void SetLanguageComboBox()
            {

                DataTable dt;

                dt = new DataTable();

                dt.Columns.Add("VALUE");
                dt.Columns.Add("DISPLAY");

                DataRow dr;

                dr = dt.Rows.Add();

                dr["VALUE"] = "en-US";
                dr["DISPLAY"] = "en-US";

                dr = dt.Rows.Add();

                dr["VALUE"] = "ja-JP";
                dr["DISPLAY"] = "ja-JP";

                dr = dt.Rows.Add();

                dr["VALUE"] = "de-DE";
                dr["DISPLAY"] = "de-DE";

                dr = dt.Rows.Add();

                dr["VALUE"] = "es-ES";
                dr["DISPLAY"] = "es-ES";

                dr = dt.Rows.Add();

                dr["VALUE"] = "fr-FR";
                dr["DISPLAY"] = "fr-FR";

                dr = dt.Rows.Add();

                dr["VALUE"] = "it-IT";
                dr["DISPLAY"] = "it-IT";

                dr = dt.Rows.Add();

                dr["VALUE"] = "ko-KR";
                dr["DISPLAY"] = "ko-KR";

                dr = dt.Rows.Add();

                dr["VALUE"] = "pt-BR";
                dr["DISPLAY"] = "pt-BR";

                dr = dt.Rows.Add();

                dr["VALUE"] = "fr-FR";
                dr["DISPLAY"] = "fr-FR";

                dr = dt.Rows.Add();

                dr["VALUE"] = "ru-RU";
                dr["DISPLAY"] = "ru-RU";

                dr = dt.Rows.Add();

                dr["VALUE"] = "zh-CN";
                dr["DISPLAY"] = "zh-CN";

                dr = dt.Rows.Add();

                dr["VALUE"] = "zh-HK";
                dr["DISPLAY"] = "zh-HK";

                this.LanguageComboBox.DataSource = dt;
                this.LanguageComboBox.ValueMember = "VALUE";
                this.LanguageComboBox.DisplayMember = "DISPLAY";

                dt = new DataTable();

                dt.Columns.Add("VALUE");
                dt.Columns.Add("DISPLAY");

                dr = dt.Rows.Add();

                dr["VALUE"] = "1";
                dr["DISPLAY"] = "1.PC/AT (101/102)";

                dr = dt.Rows.Add();

                dr["VALUE"] = "2";
                dr["DISPLAY"] = "2.Korea PC/AT 101 /MS Natural Keyboard (Type 1)";

                dr = dt.Rows.Add();

                dr["VALUE"] = "3";
                dr["DISPLAY"] = "3.Korea PC/AT 101 /MS Natural Keyboard (Type 2)";

                dr = dt.Rows.Add();

                dr["VALUE"] = "4";
                dr["DISPLAY"] = "4.Korea PC/AT 101 /MS Natural Keyboard (Type 3)";

                dr = dt.Rows.Add();

                dr["VALUE"] = "5";
                dr["DISPLAY"] = "5.Korea (103/106)";

                dr = dt.Rows.Add();

                dr["VALUE"] = "6";
                dr["DISPLAY"] = "6.Japan (106/109)";

                this.keyBoardComboBox.DataSource = dt;
                this.keyBoardComboBox.ValueMember = "VALUE";
                this.keyBoardComboBox.DisplayMember = "DISPLAY";

            }


            private bool IsInputCheck()
            {

                if (this.TargetDriveComboBox.SelectedIndex == -1)
                {
                    MessageBox.Show(_currentResource.GetString("Message9"), Application.ProductName, MessageBoxButtons.OK, MessageBoxIcon.Warning);
                    return false;
                }

                DriveInfo driveItem = new DriveInfo(this.TargetDriveComboBox.SelectedValue.ToString());
                if (driveItem.RootDirectory.GetDirectories().Count() > 0 || driveItem.RootDirectory.GetFiles().Count() > 0)
                {
                    MessageBox.Show(_currentResource.GetString("Message10"), Application.ProductName, MessageBoxButtons.OK, MessageBoxIcon.Warning);
                    return false;
                }

                if (string.IsNullOrEmpty(this.installWimTextBox.Text))
                {
                    MessageBox.Show(_currentResource.GetString("Message11"), Application.ProductName, MessageBoxButtons.OK, MessageBoxIcon.Warning);
                    return false;
                }

                if (!File.Exists(this.installWimTextBox.Text))
                {
                    MessageBox.Show(_currentResource.GetString("Message12"), Application.ProductName, MessageBoxButtons.OK, MessageBoxIcon.Warning);
                    return false;
                }

                if (string.IsNullOrEmpty(this.windowsAIKPathTextBox.Text))
                {
                    MessageBox.Show(_currentResource.GetString("Message13"), Application.ProductName, MessageBoxButtons.OK, MessageBoxIcon.Warning);
                    return false;
                }

                if (!Directory.Exists(this.windowsAIKPathTextBox.Text))
                {
                    MessageBox.Show(_currentResource.GetString("Message14"), Application.ProductName, MessageBoxButtons.OK, MessageBoxIcon.Warning);
                    return false;
                }

                return true;

            }

            private string GetAvailableDriveLetter()
            {

                List<string> allDriveLetters = new List<string>();


                for (int driveAsciiIndex = Convert.ToInt32('H'); driveAsciiIndex <= Convert.ToInt32('Z'); driveAsciiIndex++)
                {
                    string driveName = string.Format("{0}:", Convert.ToChar(driveAsciiIndex));
                    allDriveLetters.Add(driveName);

                }

                List<DriveInfo> usedDriveLetters = DriveInfo.GetDrives().ToList();

                foreach (DriveInfo useDriveItem in usedDriveLetters)
                {
                    if (allDriveLetters.Contains(useDriveItem.Name))
                    {
                        allDriveLetters.Remove(useDriveItem.Name);
                    }

                }

                string result = string.Empty;
                if (allDriveLetters.Count > 0)
                {
                    result = allDriveLetters[0];
                }

                return result;

            }


            private void ExecuteDiskPartCommand(List<string> scriptList)
            {
                string scriptFile = System.IO.Path.GetTempFileName();
                System.IO.File.WriteAllLines(scriptFile, scriptList.ToArray());

                string argument = string.Format("/S \"{0}\"", scriptFile);
                ExecuteCommand("diskpart", argument);

            }


            private void ExecuteCommand(string command, string argument)
            {
                using (Process p = new Process())
                {

                    p.StartInfo.FileName = command;
                    p.StartInfo.Arguments = argument;
                    p.Start();

                    p.WaitForExit();

                }

            }


            private void UpdateStepPanel(Panel targetPanel)
            {
                List<Panel> panelList = new List<Panel>();

                panelList.Add(this.Step1Panel);
                panelList.Add(this.Step2Panel);
                panelList.Add(this.Step3Panel);
                panelList.Add(this.Step4Panel);


                foreach (Panel panelItem in panelList)
                {

                    if (object.ReferenceEquals(panelItem, targetPanel))
                    {
                        panelItem.BackColor = Color.SpringGreen;
                        panelItem.Controls[0].ForeColor = Color.White;


                    }
                    else
                    {
                        panelItem.BackColor = System.Drawing.SystemColors.ControlDarkDark;
                        panelItem.Controls[0].ForeColor = Color.Black;

                    }

                }


            }



            private void LocalizeEnglish()
            {
                this.JapaneseToolStripMenuItem.Checked = false;
                this.EnglishToolStripMenuItem.Checked = true;

                System.Reflection.Assembly asm = System.Reflection.Assembly.GetExecutingAssembly();
                _currentResource = new System.Resources.ResourceManager(asm.GetName().Name + ".Resource_En", asm);

                this.LanguageComboBox.SelectedValue = "en-US";

                LocalizeApplication();

            }


            private void LocalizeJapanease()
            {
                this.JapaneseToolStripMenuItem.Checked = true;
                this.EnglishToolStripMenuItem.Checked = false;

                System.Reflection.Assembly asm = System.Reflection.Assembly.GetExecutingAssembly();
                _currentResource = new System.Resources.ResourceManager(asm.GetName().Name + ".Resource_Ja", asm);

                this.LanguageComboBox.SelectedValue = "ja-JP";
                this.keyBoardComboBox.SelectedValue = "6";

                LocalizeApplication();

            }


            private void LocalizeApplication()
            {
                this.TargetDriveLabel.Text = _currentResource.GetString("TargetDriveLabel");
                this.targetDriveExplainLabel.Text = _currentResource.GetString("TargetDriveExplain");

                this.InstallWimLabel.Text = _currentResource.GetString("WimLabel");
                this.InstallWimExplainLabel.Text = _currentResource.GetString("WimExplain");

                this.windowsAIKLabel.Text = _currentResource.GetString("AikLabel");
                this.windowsAIKExplainLabel.Text = _currentResource.GetString("AikExplain");

                this.ProgressLabel.Text = _currentResource.GetString("ProgressLabel");

                this.runButton.Text = _currentResource.GetString("RunButton");

                this.LanguageLabel.Text = _currentResource.GetString("LanguageLabel");
                this.keyBoardLabel.Text = _currentResource.GetString("KeyboardLabel"); 

            }

        #endregion

    }
}



